第 2 步 - 缩放和旋转地图

使用捏合操纵器可以使用户在 Kanzi 应用程序中缩放和旋转节点。为了计算缩放和旋转节点的量,捏合手势持续跟踪设备屏幕上两个手指之间的位置和位置。

使用多击操纵器可以使用户在 Kanzi 应用程序中多击或多敲节点。您可在多击操纵器中设置轻敲次数和Kanzi 两次轻敲之间的最长时间,以将多次轻敲解释为多击手势。

这一步中首先使用捏合手势实现地图的缩放和旋转。然后使用多击操纵器实现地图位置、缩放水平和旋转角度的重置。

在 Android 设备上部署该教程应用程序,因为捏合手势需要多击支持。

缩放和旋转地图

这一节中,您将创建和使用捏合操纵器,在用户捏合地图时缩放和旋转地图。

要缩放和旋转地图:

  1. pan_zoom_tap.cpp 文件中,在 PanZoomTap 类的私有部分定义捏合消息的处理程序:
    private: 
    
        ...
    
        //为 PinchManipulator::StartedMessage 消息定义处理程序,该消息来自 
        //具有可生成捏合消息的输入操纵器的 2D 节点。
        //此处理程序可为捏合手势准备 2D 节点。
        void onPinchStarted(PinchManipulator::StartedMessageArguments& messageArguments)
        {
            //从消息参数获得用户捏合的节点。
            Node2DSharedPtr mapNode = dynamic_pointer_cast<Node2D>(messageArguments.getSource());
    
            //存储渲染变换 (Render Transformation) 属性缩放 (Scale) 属性字段的初始值。
            SRTValue2D nodeTransform = mapNode->getRenderTransformation();
            m_pinchInitialScaleFactor = nodeTransform.getScale().getX() - 1.0f;
    
            //根据应用程序屏幕的大小计算最小比例值。
            ScreenSharedPtr screen = getScreen();
            m_minScale = max(getScreen()->getActualWidth() / mapNode->getActualWidth(), screen->getActualHeight() / mapNode->getActualHeight());
        }
    
        //为 PinchManipulator::MovedMessage 消息定义处理程序,该消息来自 
        //具有可生成捏合消息的输入操纵器的 2D 节点。
        //这样可按捏合手势的量缩放和旋转 2D 节点。
        void onPinchMoved(PinchManipulator::MovedMessageArguments& messageArguments)
        {
            //从消息参数获得用户捏合的节点。
            Node2DSharedPtr mapNode = dynamic_pointer_cast<Node2D>(messageArguments.getSource());
    
            //从消息参数获取比例和旋转。
            float scaleDelta = messageArguments.getScale();
            float rotateDelta = messageArguments.getRotation();
    
            //通过添加初始比例到捏合值计算比例。
            //限制比例,使得地图不小于应用程序屏幕的大小。
            float scale = max(m_minScale, scaleDelta + m_pinchInitialScaleFactor);
    
            //获取 Map 节点的渲染变换 (Render Transformation) 属性。
            SRTValue2D mapRenderSRT = mapNode->getRenderTransformation();
    
            //应用旋转。
            mapRenderSRT.rotate(rotateDelta);
    
            //应用比例。
            mapRenderSRT.setScale(Vector2(scale, scale));
    
            //获取 Map 节点的世界变换。
            //在该教程的下一步使用。
            Matrix3x3 mapWorldTransform = mapNode->getWorldTransform();
            SRTValue2D mapWorldSRT = *SRTValue2D::create(mapWorldTransform);
    
            //应用新渲染变换到 Map 节点。
            mapNode->setRenderTransformation(mapRenderSRT);
        }
    
         //为捏合手势的初始比例因子定义成员变量。
        float m_pinchInitialScaleFactor;
    
        //为最小比例值定义成员变量。
        float m_minScale;
    };
  2. PanZoomTap 类的公有部分开始处添加构造函数,并为该捏合手势设置初始比例因子:
    public: 
    
        PanZoomTap() : 
            m_pinchInitialScaleFactor(0.0f)
        {
        }
    
        ...
  3. onProjectLoaded() 函数中创建 PinchManipulator 操纵器并订阅 Map 节点的消息:
        virtual void onProjectLoaded() KZ_OVERRIDE
        {
            ...
    
            //创建生成捏合消息的输入操纵器。
            PinchManipulatorSharedPtr pinchManipulator = PinchManipulator::create(domain);
    
            //添加输入操纵器到 Map 节点。
            mapNode->addInputManipulator(pinchManipulator);
    
            //订阅 Map 节点的 PinchManipulator::StartedMessage 消息。
            // PinchManipulator 在用户在 Map 节点按下两根手指时生成此消息。
            mapNode->addMessageHandler(PinchManipulator::StartedMessage, bind(&PanZoomTap::onPinchStarted, this, placeholders::_1));
    
            //订阅 Map 节点的 PinchManipulator::MovedMessage 消息。
            //PinchManipulator 在超出比例或旋转阈值时生成此消息,
            //并在被跟踪触摸在更新之间移动时生成此消息。
            mapNode->addMessageHandler(PinchManipulator::MovedMessage, bind(&PanZoomTap::onPinchMoved, this, placeholders::_1));
        }
  4. 在 Android 设备上部署该应用程序,因为捏合手势需要多击支持:
    1. 将 Android 设备连接到计算机。
    2. Kanzi Studio 主菜单中选择 文件 (File) > 导出 (Export) > 构建 Android 包 (Build Android Package)
      Kanzi StudioKanzi Studio 工程创建一个 Android 包,然后部署到您的 Android 设备上并运行。

    在您的 Android 设备上使用捏合手势缩放和旋转地图。
    地图围绕其中心点旋转,因为 Map 节点的原点被设置为中心。

重置位置、缩放水平和旋转

在本节中,您将使用多击操纵器在用户双敲地图时重置地图的位置、缩放水平和旋转角度。

要重置位置、缩放水平和旋转:

  1. pan_zoom_tap.cpp 文件中,在 PanZoomTap 类的私有部分定义多击消息的处理程序:
    private: 
    
        ...
        //为 MultiClickManipulator::MultiClickMessage 消息定义处理程序,该消息来自 
        //具有可在用户双敲节点时生成多击消息的输入操纵器的节点。
        void onNodeDoubleTapped(MultiClickManipulator::MultiClickMessageArguments& messageArguments)
        {
            //从消息参数获取用户双敲的节点。
            Node2DSharedPtr mapNode = dynamic_pointer_cast<Node2D>(messageArguments.getSource());
    
            //移除该节点的渲染变换 (Render Transformation) 属性。
            //这样即可重置 Map 节点的位置、缩放水平和旋转角度。
            mapNode->removeLocalValue(Node2D::RenderTransformationProperty);
        }
    
        ...
    };
  2. onProjectLoaded() 函数中创建并配置 MultiClickManipulator 操纵器并订阅 Map 节点的消息:
        virtual void onProjectLoaded() KZ_OVERRIDE
        {
            ...
    
            //创建生成多击消息的输入操纵器。
            MultiClickManipulatorSharedPtr multiClickManipulator = MultiClickManipulator::create(domain);
    
            //添加输入操纵器到Map 节点。
            mapNode->addInputManipulator(multiClickManipulator);
    
            //默认情况下,输入操纵器将两次轻敲识别为双敲手势。
            //要使用不同次数的轻敲,使用 MultiClickManipulator::setExpectedClicks 函数。
            //例如,将输入操纵器设置为将三次轻敲识别为多击手势,将 3 传递给该函数。
            // multiClickManipulator->setExpectedClicks(3);
    
            //将双敲超时设置为 300 ms。如果两次轻敲之间的时间未超出该值,
            //输入操纵器将这些轻敲识别为双敲手势。默认超时为 250 ms。
            multiClickManipulator->setTimeout(chrono::milliseconds(300));
    
            //订阅Map 节点的 MultiClickManipulator::MultiClickMessage 消息。
            // MultiClickManipulator 操纵器在用户双敲节点时生成此消息。
            mapNode->addMessageHandler(MultiClickManipulator::MultiClickMessage, bind(&PanZoomTap::onNodeDoubleTapped, this, placeholders::_1));
        }
  3. 构建应用程序并将其部署到 Android 设备。
    在该应用程序中,首先使用捏合手势缩放和旋转地图,再使用平移手势移动地图。然后双敲地图将其设置为初始位置、缩放水平和旋转角度。

另请参阅

要详细了解捏合操纵器,请参阅使用捏合操纵器

要详细了解多击操纵器,请参阅使用多击操纵器

要详细了解部署 Kanzi 应用程序到 Android,请参阅部署 Kanzi 应用程序到 Android


< 上一步
下一步 >